/*
 * GLCanvasPane.cpp
 */

#include "GLCanvasPane.h"

BEGIN_EVENT_TABLE(GLCanvasPane, wxGLCanvas)
   EVT_SIZE(GLCanvasPane::OnSize)
   EVT_PAINT(GLCanvasPane::OnPaint)
   EVT_CHAR(GLCanvasPane::OnChar)
   EVT_MOUSE_EVENTS(GLCanvasPane::OnMouseEvent)
   EVT_ERASE_BACKGROUND(GLCanvasPane::OnEraseBackground)
END_EVENT_TABLE()

GLCanvasPane::GLCanvasPane(wxWindow* parent, wxWindowID winid,
       const wxPoint& pos, const wxSize& size, long style,
       const wxString& name, int *gl_attrib)
 : wxGLCanvas(parent, winid, pos, size, style, name){

        parent->Show(true);
        SetCurrent();

        smooth = GL_TRUE;
        lighting = GL_TRUE;
        display_type = 1;

        Init();
        Scale();

}
void GLCanvasPane::OnPaint( wxPaintEvent& WXUNUSED(event) ) {
   // This is a dummy, to avoid an endless succession of paint messages.
   // OnPaint handlers must always create a wxPaintDC.
   wxPaintDC dc(this);

#ifndef __WXMOTIF__
   if (!GetContext()) return;
#endif

   SetCurrent();

   Draw1();
   SwapBuffers();
}
void GLCanvasPane::OnSize(wxSizeEvent& event) {
   wxGLCanvas::OnSize(event);

   int w, h;
   GetClientSize(&w, &h);
        #ifndef __WXMOTIF__
           if (GetContext())
        #endif
   {
       SetCurrent();
       glViewport(0, 0, (GLint) w, (GLint) h);
   }
}

void GLCanvasPane::OnChar(wxKeyEvent& event) {
   switch( event.GetKeyCode() )
   {
   case WXK_ESCAPE:
       wxTheApp->ExitMainLoop();
       return;

   case WXK_LEFT:
       yrot -= 15.0;
       break;

   case WXK_RIGHT:
       yrot += 15.0;
       break;

   case WXK_UP:
       xrot += 15.0;
       break;

   case WXK_DOWN:
       xrot -= 15.0;
       break;

   default:
       event.Skip();
       return;
   }

   Refresh(false);
}
void GLCanvasPane::OnMouseEvent(wxMouseEvent& event) {
   static int dragging = 0;
   static float last_x, last_y;

   if(event.LeftIsDown())
   {
       if(!dragging)
       {
           dragging = 1;
       }
       else
       {
           yrot += (event.GetX() - last_x)*1.0;
           xrot += (event.GetY() - last_y)*1.0;
           Refresh(false);
       }
       last_x = event.GetX();
       last_y = event.GetY();
   }
   else
       dragging = 0;

}
void GLCanvasPane::OnEraseBackground( wxEraseEvent& WXUNUSED(event) ) {
   // Do nothing, to avoid flashing.
}
void GLCanvasPane::SetDataPointer(GeoData *ptr, int x, int y) {
        data = ptr;
        width = x;
        length = y;
        data->CalcRange(max, min);
}
void GLCanvasPane::Draw1()
{
   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
   glPushMatrix();
   glLoadIdentity();

   if(display_type == 0){
           HeightMap();
   }
   else if(display_type == 1){
           DrawSurface();
   }

   glPopMatrix();

   glFlush();
}

void GLCanvasPane::DrawSurface() {
	//GLint i;
	int z, x, index;

	glRotatef( yrot, 0.0f, 1.0f, 0.0f );
	glRotatef( xrot, 1.0f, 0.0f, 0.0f );
	int doctor = 2.25;
	float scale = 2.0f / MAX(width - 1, length - 1);

	glScalef(scale, scale, scale);
	glTranslatef(-(float)(width-1)/2, -0.5f, -(float)(length-1)/2);

	for(z = 0; z < length - 1; z++) {
			glBegin(GL_TRIANGLE_STRIP);
			for(x = 0; x < width; x++) {
					index = GetColorIndex(x, z);
					glColor3f(Rainbow[index].Red, Rainbow[index].Green, Rainbow[index].Blue);
					glVertex3f(x, doctor*GetHeight(x, z), z);
					index = GetColorIndex(x, z+1);
					glColor3f(Rainbow[index].Red, Rainbow[index].Green, Rainbow[index].Blue);
					glVertex3f(x, doctor*GetHeight(x, z+1), z+1);
			}
			glEnd();
	}
}
void GLCanvasPane::HeightMap() {
	//GLint i;
	int y, x, index;
	int w, h;
	GetClientSize(&w, &h);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(0.0, (double)w / (double)h, 1.0, 5.0);

	float scale = 2.0f / MAX(width - 1, length - 1);
	glScalef(scale, scale, scale);

	glTranslatef(-(float)(width-1)/2, -(float)(length-1)/2, 0.0f);


	for(y = 0; y < length - 1; y++) {
			glBegin(GL_TRIANGLE_STRIP);
			for(x = 0; x < width; x++) {
					index = GetColorIndex(x, y);
					glColor3f(Rainbow[index].Red, Rainbow[index].Green, Rainbow[index].Blue);
					glVertex3f(x, y, 1);
					index = GetColorIndex(x, y+1);
					glColor3f(Rainbow[index].Red, Rainbow[index].Green, Rainbow[index].Blue);
					glVertex3f(x, y+1, 1);
			}
			glEnd();
	}
}
void GLCanvasPane::Init() {
	//int w, h;
	//GetClientSize(&w, &h);

	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

	glShadeModel(GL_SMOOTH);
	glEnable(GL_DEPTH_TEST);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	//gluPerspective(45.0, (double)w / (double)h, 1.0, 200.0);
	glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 200.0 );

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glTranslatef( 0.0, 0.0, -6.0 );

}
void GLCanvasPane::Scale() {
	int i;
	double r;
	for (i=0, r=0.0; i<200; i++, r+=.005) {
			Rainbow[i].Red = 0.0;
			Rainbow[i].Green = r;
			Rainbow[i].Blue = 1.0;
	}
	for (i=0, r=1.0; i<200; i++, r-=.005) {
			Rainbow[200+i].Red = 0.0;
			Rainbow[200+i].Green = 1.0;
			Rainbow[200+i].Blue = r;
	}
	for (i=0, r=0.0; i<200; i++, r+=.005) {
			Rainbow[400+i].Red = r;
			Rainbow[400+i].Green = 1.0;
			Rainbow[400+i].Blue = 0.0;
	}
	for (i=0, r=1.0; i<200; i++, r-=.005) {
			Rainbow[600+i].Red = 1.0;
			Rainbow[600+i].Green = r;
			Rainbow[600+i].Blue = 0.0;
	}
	for (i=0, r=0.0; i<200; i++, r+=.005) {
			Rainbow[800+i].Red = 1.0;
			Rainbow[800+i].Green = 0.0;
			Rainbow[800+i].Blue = r;
	}
}
GLCanvasPane::~GLCanvasPane() {

}
